<?php
declare (strict_types=1);

namespace app\service\controller;

use app\BaseController;
use Swoole\Process;
use think\Exception;
use think\Request;
use app\model\Schedule as Model;

class Schedule extends BaseController
{
    /**
     * 列表查询
     * @param Request $request
     * @return \think\response\Json
     * @throws \think\db\exception\DbException
     */
    public function index(Request $request)
    {
        $params = $request->param();
        $page   = isset($params['page']) ? $params['page'] : 1;
        $limit  = isset($params['limit']) ? $params['limit'] : 10;
        $where  = [];
        if (isset($params['code']) && !empty($params['code'])) {
            $where[] = ['code', 'like', "%{$params['code']}%"];
        }
        if (isset($params['name']) && !empty($params['name'])) {
            $where[] = ['name', 'like', "%{$params['name']}%"];
        }
        if (isset($params['status']) && $params['status'] != '') {
            $where[] = ['status', '=', $params['status']];
        }
        $pageLimit = [
            'page'      => $page,
            'list_rows' => $limit,
        ];
        $paginate  = Model::where($where)
            ->order('id', 'desc')
            ->paginate($pageLimit);
        return $this->pageData($paginate);
    }



    /**
     * 平台添加
     *
     * @param Request $request
     * @return \think\response\Json
     */
    public function save(Request $request)
    {
        $params = array_map('trim', $request->param());
        $this->validate($params, [
            'code'          => 'require',
            'name'          => 'require',
            'cmd'           => 'require',
            'meanwhile_num' => 'require',
            'type'          => 'require',
            'value'         => 'require',
        ], [
            'code.require'          => '平台代码不能为空',
            'name.require'          => '平台名称不能为空',
            'cmd.require'           => '指令不能为空',
            'meanwhile_num.require' => '并发数不能为空',
            'type.require'          => '运行方式不能为空',
            'value.require'         => '执行时间不能为空',
        ]);
		$params['value'] = str_replace('：', ':', $params['value']);
        if ($params['type'] != '') {
            if ($params['type'] == 0) {
                if (!preg_match('/^[1-9]\d*$/', $params['value'])) {
                    return $this->error('执行时间格式错误！');
                }
            } else {
                $timeArr = explode(':', $params['value']);
                foreach ($timeArr as $key => $value) {
                    if (!preg_match('/^\d{2}$/', $value)) {
                        return $this->error('执行时间格式错误！');
                    }
                    if ($key == 0) {
                        if (intval($value) >= 24) {
                            return $this->error('执行时间格式错误！');
                        }
                    } else {
                        if (intval($value) > 60) {
                            return $this->error('执行时间格式错误！');
                        }
                    }
                }
            }
        }

        $otherData = Model::where('code', $params['code'])->find();
        if ($otherData) {
            return $this->error('任务代码已经存在');
        }
        $data   = [
            'code'          => $params['code'],
            'name'          => $params['name'],
            'cmd'           => $params['cmd'],
            'status'        => isset($params['status']) ? $params['status'] : '',
            'meanwhile_num' => $params['meanwhile_num'],
            'type'          => $params['type'],
            'value'         => $params['value'],
            'add_time'      => $request->time(),
            'desc'          => isset($params['desc']) ? $params['desc'] : '',
        ];
        $model  = new Model();
        $result = $model->save($data);
        if (!$result) {
            return $this->error();
        }
        return $this->success();
    }

    /**
     * 显示指定的资源
     *
     * @param int $id
     * @return \think\Response
     */
    public function read($id)
    {
        $dataModel = Model::find($id);
        if (!$dataModel || $dataModel->delete_time != 0) {
            return $this->error('平台信息不存在！');
        }
        return $this->repData($dataModel);
    }


    /**
     * 更新平台信息
     *
     * @param \think\Request $request
     * @param int $id
     * @return \think\Response
     */
    public function update(Request $request, $id)
    {
        $params = array_map('trim', $request->param());
        $this->validate($params, [
            'id'            => 'require',
            'code'          => 'require',
            'name'          => 'require',
            'cmd'           => 'require',
            'meanwhile_num' => 'require',
            'type'          => 'require',
            'value'         => 'require',
        ], [
            'code.id'               => '非法操作！',
            'code.require'          => '平台代码不能为空！',
            'name.require'          => '平台名称不能为空！',
            'cmd.require'           => '指令不能为空！',
            'meanwhile_num.require' => '并发数不能为空！',
            'type.require'          => '运行方式不能为空！',
            'value.require'         => '执行时间不能为空！',
        ]);
        if ($params['type'] != '') {
            if ($params['type'] == 0) {
                if (!preg_match('/^[1-9]\d*$/', $params['value'])) {
                    return $this->error('执行时间格式错误！');
                }
            } else {
                $timeArr = explode(':', str_replace('：', ':', $params['value']));
                foreach ($timeArr as $key => $value) {
                    if (!preg_match('/^\d{2}$/', $value)) {
                        return $this->error('执行时间格式错误！');
                    }
                    if ($key == 0) {
                        if (intval($value) >= 24) {
                            return $this->error('执行时间格式错误！');
                        }
                    } else {
                        if (intval($value) > 60) {
                            return $this->error('执行时间格式错误！');
                        }
                    }
                }
            }
        }
        $dataModel = Model::find($id);
        if (empty($dataModel)) {
            return $this->error('计划任务信息不存在');
        }
        $data = [
            'id'            => $params['id'],
            'name'          => $params['name'],
            'cmd'           => $params['cmd'],
            'status'        => isset($params['status']) ? $params['status'] : 0,
            'meanwhile_num' => $params['meanwhile_num'],
            'type'          => $params['type'],
            'value'         => $params['value'],
            'desc'          => isset($params['desc']) ? $params['desc'] : '',
        ];
        $result = $dataModel->save($data);
        if (!$result) {
            return $this->error();
        }
        return $this->success();
    }

    /**
     * 删除指定资源
     *
     * @param int $id
     * @return \think\Response
     */
    public function delete($id)
    {
        $dataModel = Model::find($id);
        if (!$dataModel) {
            return $this->error('计划任务信息不存在');
        }
        $result = $dataModel->where('id',$id)->delete();
        if (!$result) {
            return $this->error();
        }
        return $this->success();
    }

    /**
     * 获取正则运行的计划任务
    */
    public function runList() {
        /**
         * 获取正在运行的计划任务 eg:
         *  www       7275  0.4  1.1 279408 21296 pts/0    S+   21:23   0:00 crontab master
         *  www       7281  0.3  1.1 279408 20744 pts/0    S+   21:23   0:00 /usr/local/php/bin/php /home/wwwroot/chaojizhongtai/think crontab order/batchPull crontab_code=BATCH_PULL
         *  www       7287  0.3  1.1 279408 20744 pts/0    S+   21:23   0:00 /usr/local/php/bin/php /home/wwwroot/chaojizhongtai/think crontab refund/batchPull crontab_code=REFUND_PU
        */
        $shell = 'ps aux|grep crontab|grep -v "grep"';
        $process_info = shell_exec($shell);
        //过滤空白行
        $process_list = array_filter(explode("\n", $process_info), function($item) {
            return $item;
        });
        //获取系统计划任务名称
        $schedule_list = Model::where('status', 1)->column('code,name', 'code');
        $rep_data = [];
        foreach ($process_list as $k => $v) {
            $info = array_filter(preg_split('/\s/', $v), function ($item) {
                return $item;
            });
            $info = array_values($info);
            $item = [
                //所属用户
                'user' => $info[0] ?? '',
                //进程id
                'pid' => $info[1] ?? '',
                //CPU使用率
                'cpu_rate' => $info[2] ?? 0,
                //内存使用率
                'mem_rate' => $info[3] ?? 0,
                //开始时间
                'start_time' => $info[8] ?? 0,
                //指令
                'cmd' => $info[13] ?? 'master'
            ];
            //主定时器名称和code
            if ($info[11] == 'master') {
                $item['name'] = '主定时器';
                $item['code'] = 'master';
            } else {
                //获取计划任务名称和code eg:crontab_code=BATCH_PULL
                if (!isset($info[14])) {
                    continue;
                }
                $list = explode('=', $info[14]);
                if (count($list) < 2) {
                    continue;
                }
                $code = $list[1];
                $item['name'] = $schedule_list[$code] ?? '';
                $item['code'] = $code;
            }
            $rep_data[] = $item;
        }
        return $this->repData($rep_data);
    }

    /**
     * 终止计划任务
    */
    public function killProcess($pid) {
        try {
            $ret = Process::kill($pid, SIGTERM);
            if ($ret) {
                return $this->success('终止成功');
            }
            return $this->error('终止失败');
        } catch (Exception $e) {
            return $this->error($e->getMessage());
        }
    }
}
